package com.yami.shop.platform.task;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.yami.shop.bean.event.BusinessAddAirdropPersonnftEvent;
import com.yami.shop.bean.event.BusinessAddBuyPersonnftEvent;
import com.yami.shop.bean.event.BusinessAddMallSharePersonnftEvent;
import com.yami.shop.bean.model.BusinessNft;
import com.yami.shop.bean.model.BusinessNftRecord;
import com.yami.shop.bean.model.ProdNft;
import com.yami.shop.common.config.Constant;
import com.yami.shop.common.util.DataWebService;
import com.yami.shop.common.util.RedisUtil;
import com.yami.shop.config.ShopConfig;
import com.yami.shop.nft.common.model.NftDaw;
import com.yami.shop.nft.common.service.NftDawService;
import com.yami.shop.personnft.common.model.PersonNft;
import com.yami.shop.personnft.common.service.PersonNftService;
import com.yami.shop.service.BusinessNftRecordService;
import com.yami.shop.service.BusinessNftService;
import com.yami.shop.service.ProdNftService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

import java.util.*;


/**
 * @author yami
 */
@Slf4j
@Component
@AllArgsConstructor
public class BusinessNftTask {

    private BusinessNftService businessNftService;

    private ProdNftService prodNftService;

    private NftDawService nftDawService;

    private BusinessNftRecordService businessNftRecordService;

    private ApplicationEventPublisher eventPublisher;

    @Autowired
    private DataWebService dataWebService;
    @Autowired
    private ShopConfig shopConfig;
    @Autowired
    private PersonNftService personNftService;


    @XxlJob("businessNftTask")
    public void businessNftTask() {
        if (!RedisUtil.hasKey("businessNftTask")) {
            log.info("获取币任务开始----------------------");
            BusinessNft infoLast = businessNftService.getInfoLast();
            if (ObjectUtil.isNull(infoLast)) {
                log.info("暂无取币业务数据，获取币任务结束----------------------");
                return;
            }
            if (RedisUtil.hasKey("businessNftTask::" + infoLast.getBusinessNftId())) {
                return;
            }
            RedisUtil.set("businessNftTask::" + infoLast.getBusinessNftId(), "true", 120);
            if (ObjectUtil.isNotEmpty(infoLast)) {
                List<NftDaw> nftDaws = null;
                if(infoLast.getBusinessType()==11){
                    //mall4j分享
                    if (checkPersonNftCount(infoLast)){
                        RedisUtil.del("businessNftTask::" + infoLast.getBusinessNftId());
                        return;
                    }
                }else if(infoLast.getBusinessType()==10){
                    //mall4j持仓
                    nftDaws = getNftDawList(infoLast);
                    if (nftDaws == null) {
                        RedisUtil.del("businessNftTask::" + infoLast.getBusinessNftId());
                        return;
                    }
                }else{
                    ProdNft dataByProdId = null;
                    try {
                        dataByProdId = prodNftService.getDataByProdId(Long.valueOf(infoLast.getProdId()));
                    }catch (Exception e){
                        log.info("商品绑定币信息获取失败,{}",infoLast.getBusinessNftId());
                    }
                    if (ObjectUtil.isNull(dataByProdId)) {
                        infoLast.setStatus(1);
                        infoLast.setReason("商品绑定币信息获取失败");
                        infoLast.setUpdateTime(new Date());
                        businessNftService.updateById(infoLast);
                        return;
                    }
                    nftDaws = nftDawService.selectDawListLimit(dataByProdId.getDenomId(), infoLast.getNum());
                    if (nftDaws.isEmpty()) {
                        infoLast.setStatus(1);
                        infoLast.setReason("取币失败");
                        infoLast.setUpdateTime(new Date());
                        businessNftService.updateById(infoLast);
                        return;
                    }
                    // 除空投业务场景外，其他场景均无部分成功，取不到币或取不够币直接失败
                    infoLast.setStatus(2);
                    infoLast.setUpdateTime(new Date());
                    if (nftDaws.size() != infoLast.getNum()) {
                        // 类型 0：订单取币 1：开盲盒取币 2：合成取币，4零元购 5 提现空投  9空投取币
                        // 除空投业务场景外，其他场景均无部分成功，取不到币或取不够币直接失败
                        if (infoLast.getBusinessType() == 9) {
                            infoLast.setStatus(3);
                        } else {
                            infoLast.setStatus(1);
                        }
                    }
                    businessNftService.updateById(infoLast);
                }
                if (infoLast.getStatus() != 1) {
                    //从铸币方取币
                    if(infoLast.getBusinessType() != 11){
                        List<BusinessNftRecord> businessNftRecords = new ArrayList<>();
                        for (NftDaw nftDaw : nftDaws) {
                            BusinessNftRecord businessNftRecord = new BusinessNftRecord();
                            businessNftRecord.setBusinessNftId(infoLast.getBusinessNftId());
                            businessNftRecord.setProdName(infoLast.getProdName());
                            businessNftRecord.setProdId(infoLast.getProdId());
                            businessNftRecord.setUserId(infoLast.getUserId());
                            businessNftRecord.setStatus(0);
                            businessNftRecord.setDenomId(nftDaw.getDenomId());
                            businessNftRecord.setDawId(nftDaw.getDawId());
                            businessNftRecord.setNftCode(nftDaw.getNftCode());
                            businessNftRecord.setCreateTime(new Date());
                            businessNftRecords.add(businessNftRecord);
                            if (infoLast.getBusinessType() != 10) {
                                nftDaw.setUseStatus(1);
                                nftDaw.setVersion(ObjectUtil.isNull(nftDaw.getVersion()) ? 1 : nftDaw.getVersion() + 1);
                                nftDaw.setUpdateTime(new Date());
                                nftDawService.updateById(nftDaw);
                            }
                        }
                        businessNftRecordService.saveBatch(businessNftRecords);
                    }
                    // 更新状态为下游处理中
                    businessNftService.updateStatus(infoLast.getBusinessNftId(), 7, null);
                    RedisUtil.set("businessNftTaskBusinessId::" + infoLast.getBusinessNftId(), infoLast.getBusinessNftId(), 0);
                    // 异步通知下游处理
                    if (infoLast.getBusinessType() == 0 || infoLast.getBusinessType() == 1) {
                        //速度优先 // 订单取币 // 开盲盒取币
                        eventPublisher.publishEvent(new BusinessAddBuyPersonnftEvent(infoLast));
                    } else if (infoLast.getBusinessType() == 2 || infoLast.getBusinessType() == 4 || infoLast.getBusinessType() == 5 || infoLast.getBusinessType() == 9 || infoLast.getBusinessType() == 10) {
                        // 合成取币  // 零元购取币  // 提现取币 // 空投取币 // 下游购买
                        eventPublisher.publishEvent(new BusinessAddAirdropPersonnftEvent(infoLast));
                    }else if(infoLast.getBusinessType() == 11){
                        //mall4j分享
                        eventPublisher.publishEvent(new BusinessAddMallSharePersonnftEvent(infoLast));
                    }
                }
            }
            log.info("获取币任务结束----------------------");
        }
    }

    @Nullable
    private List<NftDaw> getNftDawList(BusinessNft infoLast) {
        List<NftDaw> nftDaws;
        String url = shopConfig.getApiGatewayUrl() + "/nft/outapi/api/nftcoin/getIncreaseUserNfts?";
        Map<String,String> params = new HashMap<>();
        params.put("applyNum", infoLast.getNum().toString());
        params.put("denomId", infoLast.getProdId());
        params.put("chainCode","dt");
        params.put("outId", infoLast.getBusinessNftId().toString());
        try {
            JSONObject jsonObject = dataWebService.hutoolPostWebService(url, params, null, null);
            if(Constant.SUCCESS_CODE == (Integer) jsonObject.get("code")){
                JSONArray obj = JSONArray.parseArray(jsonObject.get("data").toString());
                nftDaws = new ArrayList<>();
                for (Object object: obj) {
                    JSONObject jsonobject = (JSONObject)object;
                    NftDaw nftDaw = new NftDaw();
                    nftDaw.setNftCode(jsonobject.getString("code"));
                    nftDaw.setDawId(jsonobject.getString("tokenId"));
                    nftDaw.setDenomId(jsonobject.getString("denomId"));
                    nftDaws.add(nftDaw);
                }
                personNftService.getApplyIssueNftInfoByDenomId(infoLast.getProdId());
                // 除空投业务场景外，其他场景均无部分成功，取不到币或取不够币直接失败
                infoLast.setStatus(2);
                infoLast.setUpdateTime(new Date());
                businessNftService.updateById(infoLast);
                return nftDaws;
            }else{
                log.info(jsonObject.getString("msg"));
                return null;
            }
        }catch (Exception e){
            String msg = e.getMessage();
            infoLast.setStatus(1);
            infoLast.setReason(msg);
            infoLast.setUpdateTime(new Date());
            businessNftService.updateById(infoLast);
            log.info(e.getMessage());
            return null;
        }
    }

    private boolean checkPersonNftCount(
            BusinessNft infoLast) {
        //mall4j分享
        PersonNft personNft = PersonNft.builder().denomId(infoLast.getProdId()).userId(infoLast.getFromUserId()).status(0).build();
        Integer count = personNftService.listByParamCount(personNft);
        if(infoLast.getNum()>count){
            infoLast.setStatus(1);
            infoLast.setReason("持仓不足");
            infoLast.setUpdateTime(new Date());
            businessNftService.updateById(infoLast);
            return true;
        }
        return false;
    }
}
